package com.wstuo.common.rules.service;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.rules.dao.IRuleActionDAO;
import com.wstuo.common.rules.dao.IRuleConstraintDAO;
import com.wstuo.common.rules.dao.IRuleDAO;
import com.wstuo.common.rules.dao.IRulePackageDAO;
import com.wstuo.common.rules.dto.RuleDTO;
import com.wstuo.common.rules.dto.RuleQueryDTO;
import com.wstuo.common.rules.entity.Rule;
import com.wstuo.common.rules.entity.RuleAction;
import com.wstuo.common.rules.entity.RuleConstraint;
import com.wstuo.common.rules.entity.RulePackage;
import com.wstuo.common.rules.entity.RulePattern;
import com.wstuo.common.rules.parser.ProcreationDrlFiles;
import com.wstuo.common.rules.parser.RuleParser;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.security.utils.LanguageContent;
import com.wstuo.common.util.MathUtils;

/**
 * the service class of RuleService
 * 
 * @author <a href="mailto:376890523@qq.com">jeff</a>
 * @version 0.1 2010-9-28
 * */
public class RuleService implements IRuleService {
	@Autowired
	private IRulePackageDAO rulePackageDAO;
	@Autowired
	private IRuleDAO ruleDAO;
	@Autowired
	private IRuleActionDAO ruleActionDAO;
	@Autowired
	private IRuleConstraintDAO ruleConstraintDAO;
	private static final Logger LOGGER = Logger.getLogger(RuleService.class);
	private ProcreationDrlFiles procreationDrlFiles = new ProcreationDrlFiles();
	private LanguageContent lc = LanguageContent.getInstance();
	private RuleParser ruleParser = new RuleParser();
	/**
	 * entity2dto Method
	 * 
	 * @param entity
	 * @param dto
	 */
	public void entity2dto(Rule entity, RuleDTO dto) {
		if (entity.getRulePackage() != null) {
			Long rulePackageNo = entity.getRulePackage().getRulePackageNo();
			String packageName = entity.getRulePackage().getPackageName();
			dto.setRulePackageNo(rulePackageNo);
			dto.setPackageName(packageName);
		}
	}
	
	/**
	 * --------------save,remove,update Method--------------
	 * 
	 * @param dto
	 */
	@Transactional
	public void saveRule(RuleDTO dto) {
		Rule entity = new Rule();
		RuleDTO.dto2entity(dto, entity);
		if (null != dto.getRulePackageNo()) {
			RulePackage rulePackage = rulePackageDAO.findById(dto.getRulePackageNo());
			entity.setRulePackage(rulePackage);
		}
		ruleDAO.save(entity);
		dto.setRuleNo(entity.getRuleNo());
	}

	/**
	 * remove rule
	 * 
	 * @param no
	 */
	@Transactional
	public boolean removeRule(Long no) {
		boolean result = true;
		Byte delete = 1;
		Rule rule = ruleDAO.findById(no);

		if (rule.getDataFlag().equals(delete)) {
			result = false;
		} else {
			ruleDAO.delete(ruleDAO.findById(no));
		}

		return result;
	}

	/**
	 * remove rules
	 * 
	 * @param nos
	 */
	@Transactional
	public boolean removeRules(Long[] nos) {

		if (nos != null && nos.length > 0) {
			RulePackage rulePackage = ruleDAO.findById(nos[0]).getRulePackage();
			for (Long id : nos) {
				Rule rule = ruleDAO.findById(id);
				rule.getRulePackage().getRules().remove(rule);// 移除关系
				ruleDAO.delete(rule);
			}
			procreationDrlFiles.printDrlFiles(rulePackage);
		}
		return true;
	}

	/**
	 * merge rule
	 * 
	 * @param dto
	 * @return RuleDTO
	 */
	@Transactional
	public RuleDTO mergeRule(RuleDTO dto) {
		Rule entity = new Rule();
		RuleDTO.dto2entity(dto, entity);
		if (null != dto.getRulePackageNo()) {
			RulePackage rulePackage = rulePackageDAO.findById(dto.getRulePackageNo());
			entity.setRulePackage(rulePackage);
		}
		entity = ruleDAO.merge(entity);
		entity2dto(entity, dto);
		RuleDTO.entity2dto(entity, dto);
		validateRules(entity);// 验证
		procreationDrlFiles.printDrlFiles(entity);
		return dto;
	}

	/**
	 * merge rules
	 * 
	 * @param dtos
	 */
	@Transactional
	public void mergeAllRule(List<RuleDTO> dtos) {
		List<Rule> entities = new ArrayList<Rule>();
		for (RuleDTO dto : dtos) {
			Rule entity = new Rule();
			RuleDTO.dto2entity(dto, entity);
			if (null != dto.getRulePackageNo()) {
				RulePackage rulePackage = rulePackageDAO.findById(dto.getRulePackageNo());
				entity.setRulePackage(rulePackage);
			}
			entities.add(entity);
		}
		ruleDAO.mergeAll(entities);
	}

	/**
	 * 验证规则是否冲突.
	 * 
	 * @param rule
	 *            Rule Entity
	 * @return boolean
	 */
	private void validateRules(Rule rule) {
		List<Rule> rules = rule.getRulePackage().getRules();
		if (rules != null && rules.size() > 0 && rules.contains(rule)) {
			rules.remove(rule);// 移除当前要添加的这个规则
			/*for (Rule r : rules) {
				List<RuleAction> actions = r.getActions();
				if (actions != null && actions.size() > 0) {
					for (RuleAction ac : actions) {

						// if(compileActions.contains(ac)){
						//
						// //throw new ApplicationException("ERROR_HAS_CONFLICT_ACTION","");
						//
						// }
					}
				}
			}*/
		}
	}

	/**
	 * save rule
	 * 
	 * @param rule
	 */
	@Transactional
	public Long saveRuleEntity(Rule rule) {
		Long rulePackageNo = null;
		if (null != rule.getRulePackage()) {
			RulePackage rulePackage = rulePackageDAO.findById(rule.getRulePackage().getRulePackageNo());
			rulePackageNo = rule.getRulePackage().getRulePackageNo();
			// add mars
			rulePackage.getRules().add(rule);
			rule.setRulePackage(rulePackage);
			if ((rule.getCondition() != null) && (rule.getCondition().getConstraints() != null)) {
				for (RuleConstraint constraint : rule.getCondition().getConstraints()) {
					if (!MathUtils.isNum(constraint.getPropertyValue())) {
						constraint.setPropertyType(true);
					} else {
						constraint.setPropertyType(false);
					}
					constraint.setPattern(rule.getCondition());
				}
			}
			if (rule.getActions() != null) {
				for (RuleAction action : rule.getActions()) {
					action.setRule(rule);
				}
			}
		}
		ruleDAO.save(rule);
		validateRules(rule);// 验证
		return rulePackageNo;
	}

	/**
	 * 生成DRL规则文件
	 * 
	 * @param rulePackageNo
	 */
	@Transactional
	public void printDrlFiles(Long rulePackageNo) {

		RulePackage rp = rulePackageDAO.findById(rulePackageNo);

		if (rp != null) {
			procreationDrlFiles.printDrlFiles(rp);

		}
	}

	/**
	 * 生成DRL规则文件
	 * 
	 * @param rule
	 */
	@Transactional
	public void printDrlFiles(Rule rule) {

		if (rule != null) {
			procreationDrlFiles.printDrlFiles(rule);

		}
	}

	/**
	 * merge rule entity
	 * 
	 * @param rule
	 * @return RuleDTO
	 */
	@Transactional
	public Rule mergeRuleEntity(Rule rule) {
		Rule originRule = ruleDAO.findById(rule.getRuleNo());
		if (originRule == null) {
			throw new ApplicationException("ERROR_DATA_NO_LONGER_EXISTS");
		}
		if (null != originRule.getCondition().getConstraints()) {
			ruleConstraintDAO.deleteAll(originRule.getCondition().getConstraints());
		}
		if (null != originRule.getActions()) {
			ruleActionDAO.deleteAll(originRule.getActions());
		}
		for (RuleConstraint constraint : rule.getCondition().getConstraints()) {
			if (!MathUtils.isNum(constraint.getPropertyValue())) {
				constraint.setPropertyType(true);
			} else {
				constraint.setPropertyType(false);
			}
			constraint.setPattern(rule.getCondition());
		}
		for (RuleAction action : rule.getActions()) {
			action.setRule(rule);
		}
		rule = ruleDAO.merge(rule);
		printDrlFiles(rule);
		return rule;
	}

	/**
	 * --------------find Method--------------
	 * 
	 */

	/**
	 * find rule by page query
	 * 
	 * @param qdto
	 *            ,start,limit
	 * @return PageDTO
	 */
	@SuppressWarnings("unchecked")
	public PageDTO findRuleByPager(RuleQueryDTO qdto, int start, int limit, String sidx, String sord) {
		PageDTO p = ruleDAO.findPager(qdto, start, limit, sidx, sord);
		List<Rule> entities = p.getData();
		List<RuleDTO> dtos = new ArrayList<RuleDTO>();

		for (Rule entity : entities) {
			RuleDTO dto = new RuleDTO();
			entity2dto(entity, dto);
			RuleDTO.entity2dto(entity, dto);
			dto.setFlagName(entity.getRulePackage().getFlagName());
			dtos.add(dto);
		}

		p.setData(dtos);

		return p;
	}

	/**
	 * find rule by id
	 * 
	 * @param no
	 * @return RuleDTO
	 */
	public RuleDTO findRuleDTOById(Long no) {
		Rule entity = ruleDAO.findById(no);
		RuleDTO dto = new RuleDTO();
		entity2dto(entity, dto);
		RuleDTO.entity2dto(entity, dto);
		return dto;
	}

	/**
	 * find rule by id
	 * 
	 * @param no
	 * @return Rule
	 */
	@Transactional
	public Rule findRuleById(Long no) {
		Rule entity = ruleDAO.findById(no);
		if (entity != null) {
			if (entity.getActions() != null) {
				entity.getActions().size();
			}
			if (entity.getCondition() != null) {
				entity.getCondition().getConstraints().size();
			}
		}
		return entity;
	}

	/**
	 * 读取
	 * @param drlFilePath
	 * @return file to string
	 */
	public String readDrlFile(String drlFilePath) {
		// 将文本文件读取
		BufferedReader in = null;
		String line = null;
		StringBuffer text = new StringBuffer();
		try {
			in = new BufferedReader(new InputStreamReader(new FileInputStream(drlFilePath)));
			while ((line = in.readLine()) != null) {
				text.append(line + "\n");
			}
		}catch (FileNotFoundException e) {
			LOGGER.error(e.getMessage());
		}catch (UnsupportedEncodingException e) {
			LOGGER.error(e.getMessage());
		}catch (IOException e) {
			LOGGER.error(e.getMessage());
		}
		return text.toString();
	}

	/**
	 * 读取规则文件
	 * 
	 * @param drlFilePath
	 * @param rulePackageNo
	 * @return rulePackageNo
	 */
	@Transactional
	public Long importRules(String drlFilePath, Long rulePackageNo) {
		Long result = null;
		try {
			RulePackage rulePackage = ruleParser.parser(readDrlFile(drlFilePath));
			if (rulePackageNo != null) {// 仅导入相关规则
				RulePackage existRulePackage = rulePackageDAO.findById(rulePackageNo);
				// 移除重复的
				if (rulePackage.getRules() != null && rulePackage.getRules().size() > 0) {
					if (existRulePackage != null && existRulePackage.getRules().size() > 0) {
						List<Rule> newRules = rulePackage.getRules();
						for (Rule rule : existRulePackage.getRules()) {
							for (Rule rule_i : rulePackage.getRules()) {
								if (rule.getRuleName().equals(rule_i.getRuleName())) {
									newRules.remove(rule_i);
									continue;
								}
							}
						}
						existRulePackage.getRules().addAll(newRules);
					} else {
						if(rulePackage!=null){
							existRulePackage.setRules(rulePackage.getRules());
						}
					}
				}
				rulePackageDAO.save(existRulePackage);
				if(existRulePackage!=null){
					result = existRulePackage.getRulePackageNo();
				}
			} else {// 添加规则包+规则
				if (rulePackage.getPackageName().equals(lc.getContent("label.rulePackage.requestRule")) || rulePackage.getPackageName().equals(RulePackage.REQUESTFITSERVICES)) {
					rulePackage.setCreateTime(new Date());
					rulePackage.setLocation("request-rule.drl");
					rulePackage.setRuleFlag("rules");
				}
				if (rulePackage.getPackageName().equals(lc.getContent("title.rule.mailToRequest")) || rulePackage.getPackageName().equals(RulePackage.MAILTOREQUEST)) {
					rulePackage.setCreateTime(new Date());
					rulePackage.setLocation("mail-to-request-rule.drl");
					rulePackage.setRuleFlag("rules");
				}

				rulePackageDAO.save(rulePackage);
				result = rulePackage.getRulePackageNo();
			}

		} catch (Exception e) {
			LOGGER.error(e.getMessage());
		}
		return result;
	}

	/**
	 * 导出规则文件.
	 * 
	 * @param rulePackageNo
	 * @return InputStream
	 */
	@Transactional
	public InputStream exportRules(Long rulePackageNo) {

		RulePackage rulePackage = rulePackageDAO.findById(rulePackageNo);

		ByteArrayInputStream stream = new ByteArrayInputStream(rulePackage.toString().getBytes());
		return stream;
	}

	/**
	 * 创建默认的规则。
	 */
	@Transactional
	public void createDefalutRule() {
		createRequestDefaultRule();// 请求规则
		createMailToRequestDefaultRule();// 邮件转请求规则
		//createChangeDefaultRulePackage();// 变更规则
	}
	/**
	 * 变更规则
	 */
	private void createChangeDefaultRulePackage(){
		// 变更规则
		RulePackage rulePackage = new RulePackage();
		rulePackage.setCreateTime(new Date());
		rulePackage.setLocation("change-approval-rule.drl");
		rulePackage.setRuleFlag("rules");
		rulePackage.setFlagName("saveChange");
		rulePackage.setImports("com.wstuo.itsm.change.dto.ChangeDTO;");
		rulePackage.setPackageName(RulePackage.CHANGEAPPROVA);
		rulePackage.setDataFlag((byte)1);
		rulePackage.setRulePackageRemarks(lc.getContent("lable.The.default.rule.package"));
		rulePackage = rulePackageDAO.merge(rulePackage);
	}
	/**
	 * 默认请求规则
	 */
	@Transactional
	private void createRequestDefaultRule() {
		RulePackage rulePackage = new RulePackage();
		rulePackage.setCreateTime(new Date());
		rulePackage.setLocation("request-rule.drl");
		rulePackage.setRuleFlag("rules");
		rulePackage.setFlagName("saveRequest");
		rulePackage.setImports("com.wstuo.itsm.request.dto.RequestDTO;");
		rulePackage.setPackageName(RulePackage.REQUESTFITSERVICES);
		rulePackage.setDataFlag((byte)1);
		rulePackage.setRulePackageRemarks(lc.getContent("lable.The.default.rule.package"));
		rulePackage = rulePackageDAO.merge(rulePackage);

		Rule requestRule = new Rule();
		requestRule.setRuleName(lc.getContent("ruleService.createRequestDefaultRule.ruleName"));
		requestRule.setDataFlag((byte)1);
		requestRule.setSalience(100L);
		requestRule.setDescription(lc.getContent("ruleService.createRequestDefaultRule.Description"));
		requestRule.setDialect("mvel");

		// 动作
		List<RuleAction> actions = new ArrayList<RuleAction>(1);
		RuleAction action = new RuleAction();
		action.setGivenName("Helpdesk");
		action.setGivenValue("6");
		action.setAndOr("Or");
		action.setDataType("Long");

		action.setPropertyName("servicesNo");
		action.setActionName("servicesNo");
		action.setRule(requestRule);

		action.setDataFlag(((Number) 1).byteValue());
		action.setSequence(0);
		actions.add(action);
		requestRule.setActions(actions);

		// 空的条件
		RulePattern pattern = new RulePattern();
		pattern.setConstraints(new ArrayList<RuleConstraint>());
		pattern.setPatternBinding("dto");
		pattern.setPatternType("RequestDTO");
		requestRule.setCondition(pattern);
		requestRule.setRulePackage(rulePackage);// 所属包
		// 包下添加此规则
		List<Rule> rules = new ArrayList<Rule>(1);
		rules.add(requestRule);
		rulePackage.setRules(rules);
		// 打印规则
		ruleDAO.save(requestRule);
		procreationDrlFiles.printDrlFiles(requestRule);
	}


	/**
	 * 默认邮件转请求规则
	 */
	@Transactional
	private void createMailToRequestDefaultRule() {

		RulePackage rulePackage = new RulePackage();
		// 邮件转请求规则
		rulePackage.setCreateTime(new Date());
		rulePackage.setLocation("mail-to-request-rule.drl");
		rulePackage.setRuleFlag("rules");
		rulePackage.setImports("com.wstuo.itsm.request.dto.RequestDTO;");
		rulePackage.setPackageName(RulePackage.MAILTOREQUEST);
		rulePackage.setDataFlag((byte)1);
		rulePackage = rulePackageDAO.merge(rulePackage);

		// 邮件转请求规则
		Rule requestRule = new Rule();
		requestRule.setRuleName(lc.getContent("ruleService.createMailToRequestDefaultRule.ruleName"));
		requestRule.setDataFlag((byte)1);
		requestRule.setSalience(100L);
		requestRule.setDescription(lc.getContent("ruleService.createMailToRequestDefaultRule.Description"));
		requestRule.setDialect("mvel");

		// 动作
		List<RuleAction> actions = new ArrayList<RuleAction>(1);
		RuleAction action = new RuleAction();
		action.setGivenName(lc.getContent("ruleService.createMailToRequestDefaultRule.GivenName"));
		action.setGivenValue("1");
		action.setAndOr("Or");
		action.setDataType("Long");

		action.setPropertyName("companyNo");
		action.setActionName("companyNo");
		action.setRule(requestRule);

		action.setDataFlag(((Number) 1).byteValue());
		action.setSequence(0);
		actions.add(action);
		requestRule.setActions(actions);

		RuleConstraint rc = new RuleConstraint();
		rc.setAndOr("or");
		rc.setDataType("String");
		rc.setPropertyName("etitle matches");
		rc.setPropertyValue(".*Error.*");
		rc.setPropertyValueName("Error");
		rc.setSequence(1);
		rc.setPropertyType(true);
		// 空的条件
		RulePattern pattern = new RulePattern();
		List<RuleConstraint> rcs = new ArrayList<RuleConstraint>();
		rcs.add(rc);
		pattern.setConstraints(rcs);
		pattern.setPatternBinding("dto");
		pattern.setPatternType("RequestDTO");
		requestRule.setCondition(pattern);
		requestRule.setRulePackage(rulePackage);// 所属包
		// 包下添加此规则
		List<Rule> rules = new ArrayList<Rule>(1);
		rules.add(requestRule);
		rulePackage.setRules(rules);
		// 打印规则
		ruleDAO.save(requestRule);
		procreationDrlFiles.printDrlFiles(requestRule);
	}

	@Transactional
	public List<RuleDTO> findByRuleSelect() {
		List<RuleDTO> dtos = new ArrayList<RuleDTO>();
		RulePackage rulePackage = rulePackageDAO.findUniqueBy("packageName", RulePackage.PROCESSING);
		if (rulePackage != null) {
			List<Rule> li = rulePackage.getRules();
			for (Rule entity : li) {
				RuleDTO dto = new RuleDTO();
				entity2dto(entity, dto);
				RuleDTO.entity2dto(entity, dto);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@Transactional
	public Boolean findRulePackageBoolean(Long id) {
		boolean result = false;
		List<Rule> li = ruleDAO.findRuleList(id);
		if (li != null && li.size() > 0) {
			result = true;
		}
		return result;
	}

	/**
	 * 是否存在相同规则名
	 * 
	 * @param ruleName
	 * @param rulePackageNo
	 * @return boolean
	 */
	@Transactional
	public boolean existRuleName(String ruleName, Long rulePackageNo) {
		boolean result = false;
		List<Rule> li = ruleDAO.existRuleName(rulePackageNo, ruleName);
		if (li != null && li.size() > 0) {
			result = true;
		}
		return result;
	}

}
